import {ChangeDetectorRef, Component} from '@angular/core';
import {BaseApiComponent} from '../page-api/base-api.component';
import {PageVoService} from '../../service/page-vo.service';
import {ActivatedRoute, Router} from '@angular/router';
import {DocService} from '../../service/doc.service';
import {SendService} from '../../service/send.service';
import {UserService} from '../../service/user.service';
import {TpHttpService} from '../../service/tp-http.service';
import {MessageService} from '../../service/message.service';
import {RequestParamItem} from '../../entity/request-param-item';
import {InvokeDataDubbo} from '../../entity/invoke-data-dubbo';
import {InvokeUtils} from '../../utils/invoke-utils';
import {Menu} from '../../entity/menu';
import {InvokeResultDto} from '../../entity/invoke-result-dto';
import {BaseResponse} from '../../entity/base-response';
import {AlertMessage} from '../../entity/alert-message';
import {SiteService} from '../../service/site.service';
import {Option} from '../../entity/option';
import {ArrayUtils} from '../../utils/array-utils';
import {Button} from '../../entity/button';
import {HttpErrorResponse} from '@angular/common/http';

@Component({
    selector: 'app-page-invoke-dubbo',
    templateUrl: './page-invoke-dubbo.component.html',
    styleUrls: ['./page-invoke-dubbo.component.css']
})
export class PageInvokeDubboComponent extends BaseApiComponent {
    data: InvokeDataDubbo;

    /**
     * 已经保存的DEMO
     */
    demos: InvokeDataDubbo[];

    params: RequestParamItem[];

    publicStates = InvokeUtils.getPublishStatus();

    /**
     * 响应结果
     */
    invokeResult: InvokeResultDto;

    /**
     * 是否显示保存对话框
     * @type {boolean}
     */
    showSaveDialog = false;

    footerBtns: Button<PageInvokeDubboComponent>[] = <Button<PageInvokeDubboComponent>[]>[{
        text: '关闭',
        styles: '',
        action: (btn: Button<PageInvokeDubboComponent>) => btn.scope.showSaveDialog = false,
        scope: this
    }, {
        text: '保存',
        styles: 'primary-btn',
        action: (btn: Button<PageInvokeDubboComponent>) => btn.scope.saveInvokeData(false),
        scope: this
    }, {
        text: '另存为',
        styles: 'primary-btn',
        action: (btn: Button<PageInvokeDubboComponent>) => btn.scope.saveInvokeData(true),
        scope: this
    }];

    envOpts: Option[];

    constructor(protected ref: ChangeDetectorRef,
                protected pageVoService: PageVoService,
                protected activatedRoute: ActivatedRoute,
                protected router: Router,
                protected docService: DocService,
                private sendService: SendService,
                private userService: UserService,
                private siteService: SiteService,
                private httpService: TpHttpService,
                protected messageService: MessageService) {
        super(pageVoService, activatedRoute, router, docService, messageService);
    }

    protected onEnvReady() {
        if (this.api) {
            this.initRequestParams();
        }
    }

    protected onApiReady() {
        if (this.env) {
            this.initRequestParams();
        }
    }

    selectEnv(envs: Option[]) {
        this.data.envCode = envs[0].id;
    }

    /**
     * 调用Dubbo接口
     */
    invoke() {
        this.invokeResult = null;
        this.sendService.invokeDubbo(this.data).subscribe((data: BaseResponse<InvokeResultDto>) => {
            if (data.code !== 200) {
                // 响应正常
                this.messageService.add(AlertMessage.error('Dubbo接口调用失败！'));
            }
            this.invokeResult = data.data;
        }, (e: HttpErrorResponse) => {
            console.log(e);
            this.invokeResult = <InvokeResultDto>{
                status: e.status,
                responseBody: e.message
            };
            this.messageService.add(AlertMessage.error('Dubbo接口调用失败! ', 'invoke-error', 10));
        });
    }

    /**
     * 保存Dubbo接口参数
     */
    saveInvokeData(saveAs: boolean) {
        if (!this.data.name || this.data.name.length < 1) {
            this.messageService.add(AlertMessage.error('Dubbo接口调用失败！', 'error-save-param'));
            return;
        }
        if (saveAs) {
            // 另存为
            this.data.id = '';
        }
        this.sendService.saveDubbo(this.data).subscribe((response: BaseResponse<InvokeDataDubbo>) => {
            if (response && response.code === 200) {
                // 保存成功
                this.messageService.add(AlertMessage.success('接口调用参数保存成功！', 'invoke-data-save-success', 10));
                this.showSaveDialog = false;
                // 添加到当前demos
                const invokeData = response.data;
                this.data = this.setInvokeData(invokeData);
                if (this.demos) {
                    let exists = false;
                    this.demos.forEach(demo => {
                        if (demo.id === invokeData.id) {
                            exists = true;
                            demo = invokeData;
                        }
                    });
                    if (!exists) {
                        this.demos.push(invokeData);
                    }
                } else {
                    this.demos = [invokeData];
                }
            }
        });
    }

    /**
     * 获取左侧菜单路由后缀
     * @returns {string[]}
     */
    getLeftMenuRoutes(menu: Menu, page: PageInvokeDubboComponent): string[] {
        if (page.apiVersion) {
            return ['v', page.apiVersion.toString()];
        }
        if (menu.menuType === 0) {
            // RESTful
            return ['call'];
        } else if (menu.menuType === 1) {
            // Dubbo
            return ['dubbo'];
        }
        return null;
    }

    selectDemo(demos: InvokeDataDubbo[]) {
        this.data = demos[0];
    }

    deleteInvokeConf() {
        if (!this.data.id) {
            return;
        }
        this.httpService.del(`/api/invoke/${this.data.id}/dubbo`).subscribe((result: BaseResponse<boolean>) => {
            console.log(result);
            if (result.code === 200) {
                ArrayUtils.remove(this.demos, this.data);
                this.data = this.demos[0];
            }
        });
    }

    private initRequestParams() {
        // 初始化ENV
        this.initEnvOptions();

        const requestParams = this.api.requestParams;

        let params: RequestParamItem[] = null;
        if (requestParams) {
            params = InvokeUtils.getInvokeParams(requestParams, this.docService);
        }
        this.data = <InvokeDataDubbo>{
            id: '',
            name: '默认',
            docId: this.docId,
            apiKey: this.api.key,
            envCode: this.env.dubboEnvs[0],
            params: params ? (params.length > 0 ? params : null) : null,
            expanding: true,
            publicState: false
        };
    }

    private initEnvOptions() {
        this.siteService.get().subscribe(site => {
            const envOpts = [];
            const envCodes = this.env.dubboEnvs;
            if (!site.dubbo) {
                // 站点未配置dubbo
                return;
            }

            site.dubbo.forEach(item => {
                const index = ArrayUtils.indexOf(envCodes, item.code);
                if (index === -1) {
                    return;
                }
                envOpts.push(<Option>{
                    id: item.code,
                    text: item.name
                });
            });
            this.envOpts = envOpts;

            this.loadDemos();
        });
    }

    private setInvokeData(invokeData: InvokeDataDubbo) {
        return InvokeUtils.toInvokeParams(invokeData, this.api.requestParams, this.docService);
    }

    private loadDemos() {
        this.httpService.get('/api/invoke/list/dubbo/' + this.api.key).subscribe((response: BaseResponse<InvokeDataDubbo[]>) => {
            const demoList: InvokeDataDubbo[] = [this.data];
            if (response && response.code === 200 && response.data) {
                response.data.forEach(item => {
                    item.docId = this.docId;
                    item.envCode = this.getEnvCode(item.envCode);
                    demoList.push(this.setInvokeData(item));
                });
            }
            if (demoList) {
                this.demos = demoList;
            } else {
                this.demos = [];
            }
        });
    }

    private getEnvCode(envCode: string): string {
        let env: Option = null;
        this.envOpts.forEach(item => {
            if (item.id === envCode) {
                env = item;
            }
        });
        if (env) {
            return env.id;
        }
        return this.envOpts[0].id;
    }
}
